<template>
	<view ref="objBox" style="touch-action: none" :prop="opt" :change:prop="three.updatethree">
		<view class="webgl" id="webgl" style="padding-top: 0px; box-sizing: border-box;"></view>
	</view>
</template>
<script>
	export default {
		props: {
			word: {
				type: String,
				default: ''
			},
		},
		// watch: {
		// 	opt(newVal, oldVal) {
		// 		console.log('监听数据：', newVal, oldVal);
		// 	}
		// },
		data() {
			return {
				loading: false,
				opt: {}
			}
		},
		mounted() {
			let that = this;

			that.start();
		},
		methods: {
			start() {
				let that = this;
				console.log('执行！！！', that.word)
				that.loading = true
				that.opt = {
					'word': that.word,
				}
			},
		}
	}
</script>
<script module="three" lang="renderjs">
	import * as THREE from 'three';
	import TWEEN from '@tweenjs/tween.js';
	import {
		OrbitControls
	} from 'three/examples/jsm/controls/OrbitControls.js';
	import {
		GUI
	} from 'three/examples/jsm/libs/lil-gui.module.min.js';
	export default {
		data() {
			return {
				word: '',
				title: 'game_word_link',
				screenWidth: 0,
				selectedPositionStr: '',
				selectedLetterStr: '',
				round: 1,
				canvasWidth: 0,
				marginTop: 0,
				marginLeft: 0,
			}
		},
		mounted() {
			let that = this;

		},
		methods: {
			updatethree(data) {
				var that = this;
				console.log('出发了updatethree', data)
				that.word = data.word;
				that.$nextTick(() => {
					const platform = uni.getSystemInfoSync().platform;
					console.log("---platform---", platform)
					that.word = document.getElementById('currentWord').innerHTML;
					console.log("that.word===", that.word)
					// alert(platform)
					// uni.showToast({
					// 	title: platform,
					// 	icon: 'none',
					// });

					// uni.showToast({
					// 	title: '234',
					// 	icon: 'none'
					// })

					if (platform === 'h5') {
						// 在H5环境中
						// 执行相应操作
						// const query = uni.createSelectorQuery().in(that);
						// query.select('.webgl').boundingClientRect(data => {
						// 	that.marginTop = data.top;
						// 	that.marginLeft = data.left;
						// 	that.canvasWidth = data.width;
						// 	that.init()
						// }).exec();
					} else if (platform === 'mp-alipay' || platform === 'mp-weixin' || platform === 'mp-baidu' ||
						platform === 'mp-toutiao') {
						// 在小程序环境中
						// 执行相应操作
					} else if (platform === 'android' || platform === 'ios') {
						// 在App环境中
						// 执行相应操作
						const canvas = document.querySelector('.webgl');
						const rect = canvas.getBoundingClientRect();
						console.log("==============rect==============", JSON.stringify(rect));
						that.marginTop = rect.top - 50;
						that.marginLeft = rect.left;
						that.canvasWidth = rect.width;
						console.log("that.word===")
						console.log(that.word)

						that.init();
					}
				});
			},

			init() {
				var that = this;

				//场景
				const scene = new THREE.Scene();
				scene.background = new THREE.Color(0xff0000); // 将背景颜色设置为红色

				//辅助观察的坐标系
				const axesHelper = new THREE.AxesHelper(100);
				scene.add(axesHelper);

				//光源设置
				const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
				directionalLight.position.set(100, 60, 50);
				scene.add(directionalLight);
				const ambient = new THREE.AmbientLight(0xffffff, 0.4);
				scene.add(ambient);

				//相机
				const width = that.canvasWidth;
				const height = that.canvasWidth;
				const camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 1000);
				camera.position.set(0, 0, 700);
				camera.lookAt(0, 0, 700);

				// 创建一个对象来存储公共配置的参数
				const guiParams = {
					// fontColor: 'white', // 字体颜色
					// backgroundColor: 'green' // 背景颜色
					fontColor: '#ffffff', // 字体颜色
					backgroundColor: '#fff000', // 背景颜色

					selectedFontColor: '#0000ff', // 选中的字体颜色
					selectedBackgroundColor: '#00ffff', // 选中的背景颜色
					// fontColor: 0xffffff, // 字体颜色   x
					// backgroundColor: 0xfff000 // 背景颜色  x

					rows: 7, //宫格行数
					cols: 7, //宫格列数
					spacing: 0, // 模型之间的间距
				};

				// WebGL渲染器设置
				const renderer = new THREE.WebGLRenderer({
					antialias: true, //开启优化锯齿
				});
				renderer.setPixelRatio(window.devicePixelRatio); //防止输出模糊
				renderer.setSize(width, height);
				//three.js执行渲染命令会输出一个canvas画布，也就是一个HTML元素，你可以插入到web页面中
				// document.body.appendChild(renderer.domElement);
				document.getElementById('webgl').appendChild(renderer.domElement);

				if ('字母球') {
					// 创建精灵材质
					// var oldTexture = new THREE.TextureLoader().load('./image/a.png');
					// var newTexture = new THREE.TextureLoader().load('./image/0.png');

					// 批量创建精灵模型
					var spriteWidth = (width) / guiParams.cols; // 精灵的宽度  
					var spriteHeight = (height) / guiParams.rows; // 精灵的高度

					var lineWidth = spriteHeight * 1 / 5;

					// camera.position.set(spriteWidth * rows / 2, spriteHeight * rows / 2, 700)
					// camera.lookAt(spriteWidth * rows / 2, spriteHeight * rows / 2, 700);

					// // 计算相机的位置
					// var cameraX = (cols * spriteWidth + (cols + 1) * spacing) / 2;
					// var cameraY = (rows * spriteHeight + (rows + 1) * spacing) / 2;
					// var cameraZ = Math.max(width, height) / (2 * Math.tan(Math.PI * camera.fov / 360));
					// // 设置相机
					// camera.position.set(cameraX, cameraY, cameraZ);
					// camera.lookAt(cameraX, cameraY, cameraZ);


					var AllMeshArr = []; //所有的字母
					var lettersObj = {
						// "00": "a",
						// "01": "a",
						// "02": "a",
						// "03": "a",
						// "04": "a",
						// "05": "a",
						// "00": "a",
					};
					var lettersObj = {};
					for (var i = 0; i < guiParams.rows; i++) {
						for (var j = 0; j < guiParams.cols; j++) {
							lettersObj[i.toString() + j.toString()] = getRandomLetter();
						}
					}

					console.log('lettersObj', lettersObj);

					if (true) {
						if ('单条：不包括斜线' && false) {
							function generatePath(startX, startY) {
								var path = [];
								var directions = [{
										x: 0,
										y: -1
									}, // 上
									{
										x: 1,
										y: 0
									}, // 右
									{
										x: 0,
										y: 1
									}, // 下
									{
										x: -1,
										y: 0
									} // 左
								];

								var currentX = startX;
								var currentY = startY;

								path.push({
									x: currentX,
									y: currentY
								});

								while (path.length < 5) {
									var availableDirections = [];

									for (var i = 0; i < directions.length; i++) {
										var nextX = currentX + directions[i].x;
										var nextY = currentY + directions[i].y;

										if (nextX >= 0 && nextX <= 9 && nextY >= 0 && nextY <= 9) {
											if (!path.some(function(point) {
													return point.x === nextX && point.y === nextY;
												})) {
												availableDirections.push(directions[i]);
											}
										}
									}

									if (availableDirections.length === 0) {
										break;
									}

									var randomDirection = availableDirections[Math.floor(Math.random() *
										availableDirections.length)];
									currentX += randomDirection.x;
									currentY += randomDirection.y;

									path.push({
										x: currentX,
										y: currentY
									});
								}

								// 将位置信息数组转换为字符串数组
								var stringPath = path.map(function(point) {
									return point.x + "" + point.y;
								});

								return stringPath;
							}

							// 调用方法生成随机折线的位置信息数组
							var zhangtrArr = generatePath(0, 0);
						}

						if ('单条：会有斜线' && false) {
							var positionArray = [];
							var pointCount = 5; // 折线点的数量
							var maxCoordinate = 8; // 坐标的最大值

							function generateRandomLine() {
								// 清空位置信息数组
								positionArray = [];

								// 随机生成起始点的行和纵坐标
								var startX = Math.floor(Math.random() * (maxCoordinate +
									1)); // 随机生成起始点的行坐标，范围为0到maxCoordinate
								var startY = Math.floor(Math.random() * (maxCoordinate +
									1)); // 随机生成起始点的纵坐标，范围为0到maxCoordinate
								positionArray.push("" + startX + startY);

								// 循环生成剩余点的行和纵坐标
								for (var i = 1; i < pointCount; i++) {
									// 生成下一个点的行和纵坐标
									var nextX, nextY;
									do {
										// 获取上一个点的行和纵坐标
										var lastPosition = positionArray[i - 1];

										// 随机生成下一个点的行和纵坐标
										nextX = parseInt(lastPosition[0]) + Math.floor(Math.random() * 3) -
											1; // 在上一个点的行坐标上加上一个随机值，范围为-1到1
										nextY = parseInt(lastPosition[1]) + Math.floor(Math.random() * 3) -
											1; // 在上一个点的纵坐标上加上一个随机值，范围为-1到1

										// 确保下一个点的行和纵坐标在合法范围内
										nextX = Math.max(0, Math.min(maxCoordinate, nextX));
										nextY = Math.max(0, Math.min(maxCoordinate, nextY));
									} while (isDuplicate(nextX, nextY, positionArray)); // 检查下一个点是否已经存在于位置信息数组中，若存在则重新生成

									// 将下一个点的行和纵坐标组成一个字符串，并添加到位置信息数组中
									var nextPosition = "" + nextX + nextY;
									positionArray.push(nextPosition);
								}

								// 输出位置信息数组
								console.log(positionArray);

								return positionArray;
							}

							// 检查坐标是否已经存在于位置信息数组中
							function isDuplicate(x, y, array) {
								for (var i = 0; i < array.length; i++) {
									var position = array[i];
									var positionX = parseInt(position[0]);
									var positionY = parseInt(position[1]);
									if (positionX === x && positionY === y) {
										return true;
									}
								}
								return false;
							}

							// 调用方法生成随机折线的位置信息数组
							var zhangtrArr = generateRandomLine();
						}

						if ('单条：不包括斜线' && true) {
							function generatePaths(numPaths, pathLength) {
								var paths = [];

								for (var i = 0; i < numPaths; i++) {
									var path = generatePath(pathLength);
									paths.push(path);
								}

								return paths;
							}

							function generatePath(pathLength) {
								var path = [];
								var directions = [{
										x: 0,
										y: -1
									}, // 上
									{
										x: 1,
										y: 0
									}, // 右
									{
										x: 0,
										y: 1
									}, // 下
									{
										x: -1,
										y: 0
									} // 左
								];

								var startX = Math.floor(Math.random() * guiParams.rows);
								var startY = Math.floor(Math.random() * guiParams.rows);

								var currentX = startX;
								var currentY = startY;

								path.push({
									x: currentX,
									y: currentY
								});

								while (path.length < pathLength) {
									var availableDirections = [];

									for (var i = 0; i < directions.length; i++) {
										var nextX = currentX + directions[i].x;
										var nextY = currentY + directions[i].y;

										if (nextX >= 0 && nextX <= (guiParams.rows - 1) && nextY >= 0 && nextY <= (
												guiParams.rows - 1)) {
											if (!path.some(function(point) {
													return point.x === nextX && point.y === nextY;
												})) {
												availableDirections.push(directions[i]);
											}
										}
									}

									if (availableDirections.length === 0) {
										break;
									}

									var randomDirection = availableDirections[Math.floor(Math.random() *
										availableDirections.length)];
									currentX += randomDirection.x;
									currentY += randomDirection.y;

									path.push({
										x: currentX,
										y: currentY
									});
								}

								// 将位置信息数组转换为字符串数组
								var stringPath = path.map(function(point) {
									return point.x + "" + point.y;
								});

								return stringPath;
							}


							var zhangtrArr = generatePaths(1, that.word.length);
							console.log('单条：不包括斜线')
							console.log(zhangtrArr)
							console.log('单条：不包括斜线')
							zhangtrArr = Array.from(zhangtrArr[0]).concat([]);
						}

						// 获取数据
						console.log("我是张腾瑞word", that.word);
						var wordArr = new Array(); //定义一数组
						wordArr = that.word.split('');
						for (let i = 0; i < zhangtrArr.length; i++) {
							const element = zhangtrArr[i];
							lettersObj[element] = wordArr[i] + ">";
						}
						console.log(zhangtrArr);
						// lettersObj["00"] = "中";
						// lettersObj["01"] = "中";
						// lettersObj["02"] = "中";
					}

					for (var i = 0; i < guiParams.cols; i++) {
						for (var j = 0; j < guiParams.cols; j++) {
							var currentLetter = lettersObj[i.toString() + j.toString()];

							// 创建精灵模型
							var currentSprite = fnCreateSprite(currentLetter, i, j);

							AllMeshArr.push(currentSprite);
							scene.add(currentSprite);
						}
					}
				}


				if ('选择') {
					// 鼠标单击射线拾取meshArr中的某个国家Mesh
					var currentLine = null;
					var chooseMesh = null
					var chooseMeshArr = []; //选中的字母
					var selectedLetterArr = []; //选中的字母
					var selectedPositionArr = []; //选中的位置

					// 开始手势
					function startGesture(event) {
						isGestureStarted = true;
					}

					// 跟踪手势:选中物体
					function choose(event) {
						if (isGestureStarted) {
							if (chooseMesh) {
								// chooseMesh.material.color.set(0xffffff); // 把上次选中的mesh设置为原来的颜色
							}

							var Sx = event.offsetX; //鼠标单击位置横坐标
							var Sy = event.offsetY; //鼠标单击位置纵坐标【pc端不需要减去margin-top的值】
							//屏幕坐标转WebGL标准设备坐标
							var x = (Sx / that.canvasWidth) * 2 - 1; //WebGL标准设备横坐标
							var y = -(Sy / that.canvasWidth) * 2 + 1; //WebGL标准设备纵坐标
							//创建一个射线投射器`Raycaster`
							var raycaster = new THREE.Raycaster();
							//通过鼠标单击位置标准设备坐标和相机参数计算射线投射器`Raycaster`的射线属性.ray
							raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
							//返回.intersectObjects()参数中射线选中的网格模型对象
							// 未选中对象返回空数组[],选中一个数组1个元素，选中两个数组两个元素
							var intersects = raycaster.intersectObjects(AllMeshArr);
							// console.log("射线器返回的对象", intersects);
							// console.log("射线投射器返回的对象 点point", intersects[0].point);
							// console.log("射线投射器的对象 几何体",intersects[0].object.geometry.vertices)
							// intersects.length大于0说明，说明选中了模型
							if (intersects.length > 0) {
								console.log("选中啦")
								chooseMesh = intersects[0].object;
								// console.log('position:', chooseMesh.userData.position, selectedPositionArr)
								var result = selectedPositionArr.includes(chooseMesh.userData.position);
								if (result) {
									// console.log("数组中包含该元素");
								} else {
									console.log("数组中不包含该元素");

									// chooseMesh.material.color.set(0x0000ff); //选中改变颜色，这样材质颜色贴图.map和color颜色会相乘
									// chooseMesh.material.map = newTexture; // 设置新的贴图



									chooseMeshArr.push(chooseMesh)
									selectedPositionArr.push(chooseMesh.userData.position);
									selectedLetterArr.push(chooseMesh.userData.letter);

									onSpriteSelected(chooseMesh);

									if (chooseMeshArr.length >= 2) {
										var prevMesh = chooseMeshArr[chooseMeshArr.length - 2];
										console.log(prevMesh.position.clone(), chooseMesh.position.clone());
										drawLine(prevMesh.position.clone(), chooseMesh.position.clone());
									}
								}
							}
						}
					}

					// 跟踪手势:选中物体
					function choose2(event) {
						// that.aaaaa();
						// that.bbbbb();
						if (isGestureStarted) {
							if (chooseMesh) {
								// chooseMesh.material.color.set(0xffffff); // 把上次选中的mesh设置为原来的颜色
							}

							// 处理触摸移动事件
							var touch = event.touches[0];
							var Sx = touch.clientX - that.marginLeft; //鼠标单击位置横坐标
							var Sy = touch.clientY - that.marginTop - 50; //鼠标单击位置纵坐标【手机端需要减去margin-top的值】

							console.log('Sx:', Sx)
							console.log('Sy:', Sy)
							//屏幕坐标转WebGL标准设备坐标
							var x = (Sx / that.canvasWidth) * 2 - 1; //WebGL标准设备横坐标
							var y = -((Sy) / (that.canvasWidth)) * 2 + 1; //WebGL标准设备纵坐标
							//创建一个射线投射器`Raycaster`
							var raycaster = new THREE.Raycaster();
							//通过鼠标单击位置标准设备坐标和相机参数计算射线投射器`Raycaster`的射线属性.ray
							raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
							//返回.intersectObjects()参数中射线选中的网格模型对象
							// 未选中对象返回空数组[],选中一个数组1个元素，选中两个数组两个元素
							var intersects = raycaster.intersectObjects(AllMeshArr);
							// console.log("射线器返回的对象", intersects);
							// console.log("射线投射器返回的对象 点point", intersects[0].point);
							// console.log("射线投射器的对象 几何体",intersects[0].object.geometry.vertices)
							// intersects.length大于0说明，说明选中了模型
							if (intersects.length > 0) {
								console.log("选中啦")
								chooseMesh = intersects[0].object;
								// console.log('position:', chooseMesh.userData.position, selectedPositionArr)
								var result = selectedPositionArr.includes(chooseMesh.userData.position);
								if (result) {
									// console.log("数组中包含该元素");
								} else {
									console.log("数组中不包含该元素");

									// chooseMesh.material.color.set(0x0000ff); //选中改变颜色，这样材质颜色贴图.map和color颜色会相乘
									// chooseMesh.material.map = newTexture; // 设置新的贴图



									chooseMeshArr.push(chooseMesh)
									selectedPositionArr.push(chooseMesh.userData.position);
									selectedLetterArr.push(chooseMesh.userData.letter);

									onSpriteSelected(chooseMesh);
								}
							}
						}
					}

					// 结束手势
					function endGesture(event) {
						if (isGestureStarted) {
							isGestureStarted = false;
							document.getElementById("selectedPosition").innerHTML = selectedPositionArr.join(',');
							document.getElementById("selectedLetter").innerHTML = selectedLetterArr.join(',');
							// selectedPositionArr = [];
							// selectedLetterArr = [];
							// chooseMeshArr = [];
							// 在这里可以执行手势结束时的操作
							for (let index = 0; index < chooseMeshArr.length; index++) {
								const element = chooseMeshArr[index];
								console.log('aaaaa:', element)
								aaa(element); //爆炸星星特效
								// bbb(element);//背景特效
							}

							scene.remove(currentLine);
							chooseMeshArr = [];
						}
					}


					// 定义变量来记录手势解锁的状态
					let isGestureStarted = false;

					// 添加触摸或鼠标事件监听器
					renderer.domElement.addEventListener('mousedown', startGesture);
					renderer.domElement.addEventListener('mousemove', choose);
					renderer.domElement.addEventListener('mouseup', endGesture);
					renderer.domElement.addEventListener('touchstart', startGesture);
					renderer.domElement.addEventListener('touchmove', choose2);
					renderer.domElement.addEventListener('touchend', endGesture);
				}


				var explodeMeshArr = []; //爆炸模型

				// 五角星散开特效
				function aaa(circle) {
					// 创建五角星
					var starCount = 8;
					var stars = [];
					var starGeometry = new THREE.PlaneGeometry(10, 10);
					// 创建一个纹理加载器
					var textureLoader = new THREE.TextureLoader();
					// 加载图片贴图
					var texture = textureLoader.load("https://cdn.spbcn.org/miniprogram/image/star64.png");
					var starMaterial = new THREE.MeshBasicMaterial({
						map: texture,
						transparent: true,
					});

					for (var i = 0; i < starCount; i++) {
						var star = new THREE.Mesh(starGeometry, starMaterial);
						star.position.set(circle.position.x, circle.position.y, 110);
						stars.push(star);
						scene.add(star);
					}

					// 创建动画效果
					var duration1 = 0.35; // 第一段动画持续时间
					var duration2 = 0.1; // 第二段动画持续时间
					var delay = 0.001; // 延迟时间
					var targetDistance = spriteHeight * 1 / 3; // 目标距离


					var distance = 0;
					var tween1 = new TWEEN.Tween({
							distance: 0
						})
						.to({
							distance: targetDistance
						}, duration1 * 1000)
						.delay(delay * 1000)
						.easing(TWEEN.Easing.Quadratic.Out)
						.onUpdate((d) => {
							console.log("d  ===-----000", JSON.stringify(d))
							distance = d.distance;
							stars.forEach(function(star, index) {
								var angle = ((Math.PI * 2) / starCount) * index;
								var newX = circle.position.x + distance * Math.cos(angle);
								var newY = circle.position.y + distance * Math.sin(angle);
								star.position.set(newX, newY, 110);

								// 根据距离调整星星的大小
								var distanceToCenter = Math.sqrt(
									Math.pow(newX - circle.position.x, 2) +
									Math.pow(newY - circle.position.y, 2)
								);
								// var scaleFactor = distanceToCenter / 12; // 根据距离计算缩放比例
								// if (index % 2 == 1) {
								// 	star.scale.set(scaleFactor, scaleFactor, 1); // 设置星星的缩放
								// } else {
								// 	star.scale.set(
								// 		(scaleFactor - (targetDistance - distance)) / targetDistance,
								// 		(scaleFactor - (targetDistance - distance)) / targetDistance,
								// 		1
								// 	);
								// }



								if (index % 2 == 1) {
									var scaleFactor = distanceToCenter / 16; // 根据距离计算缩放比例
									star.scale.set(scaleFactor, scaleFactor, 1); // 设置星星的缩放
								} else {
									var scaleFactor = distanceToCenter / 32; // 根据距离计算缩放比例
									star.scale.set(scaleFactor, scaleFactor, 1); // 设置星星的缩放
								}
							});
						});
					var opacity = 1;
					var tween2 = new TWEEN.Tween({
							opacity: 1
						})
						.to({
							opacity: 0
						}, duration2 * 1000)
						.easing(TWEEN.Easing.Quadratic.In)
						.onUpdate(function() {
							opacity -= 0.1;
							stars.forEach(function(star) {
								// console.log("opacity", opacity);
								star.material.opacity = opacity;
							});
						})
						.onComplete(function() {
							// 在动画结束时执行一些操作，比如移除五角星
							stars.forEach(function(item) {
								scene.remove(item);
							});
							scene.add(circle);
							explodeMeshArr.forEach(function(item) {
								scene.remove(item);
							});
						});

					// 串联两段动画
					tween1.chain(tween2);

					// 开始第一段动画
					tween1.start();

					scene.remove(circle);
					// 在第一段动画结束后，开始第二段动画
					tween1.onComplete(function() {
						tween2.start();
					});
				}

				// 创建一个数组来存储每一帧的纹理
				var textures = [];
				var frameCount = 10; // 假设有10帧
				let frameDelay = 100; // Delay between frame changes in milliseconds
				let lastFrameChangeTime = 0;

				const textureLoader = new THREE.TextureLoader();
				for (let i = 0; i < frameCount; i++) {
					let texture = textureLoader.load(`./image/num/${i}.png`); // Load each frame
					textures.push(texture);
				}
				var frameIndex = 0;
				var planeMaterial = new THREE.MeshBasicMaterial({
					map: textures[frameIndex]
				});

				// 爆炸背景特效
				/**
				 * 函数bbb
				 * @param {THREE.Object3D} circle - 圆形对象
				 */
				function bbb(circle) {
					// 创建平面几何体
					const planeGeometry = new THREE.PlaneGeometry(50, 50);
					// 创建平面网格
					const plane = new THREE.Mesh(planeGeometry, planeMaterial);
					// 设置平面位置
					plane.position.set(circle.position.x, circle.position.y, 100);
					// 将平面添加到爆炸网格数组中
					explodeMeshArr.push(plane);
					// 将平面添加到场景中
					scene.add(plane);
				}

				// 画线：两球之间的连线
				function drawLine(center1, center2) {
					if (currentLine) {
						scene.remove(currentLine);
					}

					// 计算连接两个球体的连线向量
					const lineDirection = new THREE.Vector3().subVectors(center2, center1).normalize();

					// 计算线条的中心位置
					const lineCenter = new THREE.Vector3()
						.addVectors(center1, center2)
						.multiplyScalar(0.5);

					// 创建圆柱体几何体
					const cylinderGeometry = new THREE.CylinderGeometry(
						lineWidth,
						lineWidth,
						center1.distanceTo(center2),
						32
					);

					// 创建线条材质
					const cylinderMaterial = new THREE.MeshBasicMaterial({
						color: 0xffffff,
					});

					// 创建圆柱体网格对象
					const line = new THREE.Mesh(cylinderGeometry, cylinderMaterial);

					// 设置线条位置和旋转
					line.position.copy(lineCenter);
					line.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), lineDirection);
					line.position.z = -10;
					currentLine = line;
					// 将线条添加到场景中
					scene.add(line);
				}

				// 画线：鼠标跟球之间的连线
				function drawLineV2(center1, center2) {
					// 计算连接两个球体的连线向量
					const lineDirection = new THREE.Vector3().subVectors(center2, center1).normalize();

					// 计算线条的中心位置
					const lineCenter = new THREE.Vector3()
						.addVectors(center1, center2)
						.multiplyScalar(0.5);

					// 创建圆柱体几何体
					const cylinderGeometry = new THREE.CylinderGeometry(
						lineWidth,
						lineWidth,
						center1.distanceTo(center2),
						32
					);

					// 创建线条材质
					const cylinderMaterial = new THREE.MeshBasicMaterial({
						color: 0xffffff,
					});

					// 创建圆柱体网格对象
					const line = new THREE.Mesh(cylinderGeometry, cylinderMaterial);

					// 设置线条位置和旋转
					line.position.copy(lineCenter);
					line.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), lineDirection);
					// 将线条添加到场景中
					line.position.z = -10;
					scene.add(line);
					scene.remove(currentLine);
				}


				// 选中精灵模型的事件处理函数
				function onSpriteSelected(chooseMesh) {
					if (chooseMeshArr.length >= 2) {
						drawLineV2(chooseMeshArr[chooseMeshArr.length - 1].position.clone(), chooseMeshArr[chooseMeshArr
							.length - 2].position.clone());
					}

					// 获取画布
					var canvas = chooseMesh.material.map.image;
					var context = canvas.getContext('2d');

					// 修改背景颜色
					var centerX = canvas.width / 2;
					var centerY = canvas.height / 2;
					var radius = Math.min(centerX, centerY) - 10;
					context.beginPath();
					context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
					context.fillStyle = guiParams.selectedBackgroundColor;
					context.fill();

					// 在画布上绘制文字
					context.font = 'Bold 150px Arial';
					context.fillStyle = guiParams.selectedFontColor;
					context.textAlign = 'center';
					context.textBaseline = 'middle'; // 设置文本基线为middle
					context.fillText(chooseMesh.userData.letter, canvas.width / 2, canvas.height / 2);

					// 将修改后的画布重新赋值给精灵模型的材质贴图
					chooseMesh.material.map.needsUpdate = true;
				}

				// 创建精灵模型
				function fnCreateSprite(letter, i, j) {
					// var texture = new THREE.TextureLoader().load('./image/' + currentLetter + '.png');
					var texture = new THREE.CanvasTexture(fnCreateSpriteLetter(letter));
					// var spriteMaterial = new THREE.SpriteMaterial({
					//     map: texture,
					// });
					// var sprite = new THREE.Sprite(spriteMaterial);

					if ('圆模型') {
						var circleGeometry = new THREE.CircleGeometry(0.5, 32); // 半径为 spriteWidth 的圆形模型
						var circleMaterial = new THREE.MeshBasicMaterial({
							map: texture,
							// color: 0x990099,
							side: THREE.DoubleSide
						}); // 设置圆形模型的颜色为红色，您也可以自定义其他颜色
						var sprite = new THREE.Mesh(circleGeometry, circleMaterial);
					}

					// 设置精灵模型的颜色
					// sprite.material.color.set(0xff0000); // 设置红色
					// sprite.material.color.set(0x00ff00); // 设置绿色
					// sprite.material.color.set(0x0000ff); // 设置蓝色
					sprite.position.set(
						(j - Math.floor(guiParams.rows / 2)) * (spriteWidth),
						(i - Math.floor(guiParams.rows / 2)) * (spriteWidth),
						10
					);
					sprite.scale.set(spriteWidth - 12, spriteHeight - 12, 0.1);

					// 设置自定义属性
					sprite.userData.letter = letter; //设置字母
					sprite.userData.position = i.toString() + j.toString(); //设置位置

					return sprite;
				}

				// 创建精灵模型上的字母
				function fnCreateSpriteLetter(letter) {
					// 创建一个画布
					var canvas = document.createElement('canvas');
					var context = canvas.getContext('2d');

					canvas.width = 256;
					canvas.height = 256;

					// 绘制圆形背景颜色
					var _centerX = canvas.width / 2;
					var _centerY = canvas.height / 2;
					// var radius = Math.min(_centerX, _centerY) - guiParams.spacing; // 半径为画布宽度和高度的最小值减去一些空白
					var radius = Math.min(_centerX, _centerY) - guiParams.spacing; // 半径为画布宽度和高度的最小值减去一些空白
					context.beginPath();
					context.arc(_centerX, _centerY, radius, 0, 2 * Math.PI, false);
					context.fillStyle = guiParams.backgroundColor;
					context.fill();

					// 在画布上绘制文字
					context.font = 'Bold 150px Arial';
					context.fillStyle = guiParams.fontColor;
					context.textAlign = 'center';
					context.textBaseline = 'middle'; // 设置文本基线为middle
					context.fillText(letter, canvas.width / 2, canvas.height / 2);
					return canvas;
				}

				// 创建精灵模型上的字母
				function fnCreateSelectedSpriteLetter(letter) {
					// 创建一个画布
					var canvas = document.createElement('canvas');
					var context = canvas.getContext('2d');
					canvas.width = 256;
					canvas.height = 256;

					// 绘制圆形背景颜色
					var _centerX = canvas.width / 2;
					var _centerY = canvas.height / 2;
					// var radius = Math.min(_centerX, _centerY) - spacing; // 半径为画布宽度和高度的最小值减去一些空白
					var radius = Math.min(_centerX, _centerY) - 10; // 半径为画布宽度和高度的最小值减去一些空白
					context.beginPath();
					context.arc(_centerX, _centerY, radius, 0, 2 * Math.PI, false);
					context.fillStyle = guiParams.selectedBackgroundColor;
					context.fill();

					// 在画布上绘制文字
					context.font = 'Bold 150px Arial';
					context.fillStyle = guiParams.selectedFontColor;
					context.textAlign = 'center';
					context.textBaseline = 'middle'; // 设置文本基线为middle
					context.fillText(letter, canvas.width / 2, canvas.height / 2);
					return canvas;
				}

				// 数组中随机获取一个元素
				function getRandomLetter() {
					var letters_26 = [
						"a", "b", "c", "d", "e", "f", "g",
						"h", "i", "j", "k", "l", "m", "n",
						"o", "p", "q", "r", "s", "t", "u",
						"v", "w", "x", "y", "z"
					];
					var randomIndex = Math.floor(Math.random() * letters_26.length); // 生成一个随机索引值
					return letters_26[randomIndex]; // 根据随机索引值获取相应位置上的元素
				}

				if ('线跟随鼠标移动') {
					let isDragging = false;

					document.addEventListener("mousemove", onDocumentMouseMove);
					document.addEventListener("mousedown", onDocumentMouseDown);
					document.addEventListener("mouseup", onDocumentMouseUp);

					document.addEventListener("touchmove", onDocumentTouchMove);
					document.addEventListener("touchstart", onDocumentMouseDown);
					document.addEventListener("touchend", onDocumentMouseUp);

					// PC端
					function onDocumentMouseMove(event) {
						if (isDragging) {
							var Sx = event.offsetX; //鼠标单击位置横坐标
							var Sy = event.offsetY; //鼠标单击位置纵坐标【pc端不需要减去margin-top的值】

							//屏幕坐标转WebGL标准设备坐标
							var mouseX = (Sx / that.canvasWidth) * 2 - 1; //WebGL标准设备横坐标
							var mouseY = -(Sy / that.canvasWidth) * 2 + 1; //WebGL标准设备纵坐标

							const vector = new THREE.Vector3(mouseX, mouseY, 0.5);
							vector.unproject(camera);

							const dir = vector.sub(camera.position).normalize();
							const distance = -camera.position.z / dir.z;
							const pos = camera.position.clone().add(dir.multiplyScalar(distance));

							if (chooseMeshArr.length >= 1) {
								drawLine(chooseMeshArr[chooseMeshArr.length - 1].position.clone(), pos);
							}
						}
					}

					// 移动端
					function onDocumentTouchMove(event) {
						event.preventDefault(); // 阻止默认事件

						if (isDragging) {
							var touch = event.touches[0]; // 获取第一个触摸点
							var Sx = touch.clientX - renderer.domElement.getBoundingClientRect().left; // 触摸点横坐标
							var Sy = touch.clientY - renderer.domElement.getBoundingClientRect().top; // 触摸点纵坐标

							console.log("Sy------------------------------------", Sy)

							// 屏幕坐标转WebGL标准设备坐标
							var mouseX = (Sx / that.canvasWidth) * 2 - 1; // WebGL标准设备横坐标
							var mouseY = -(Sy / that.canvasWidth) * 2 + 1; // WebGL标准设备纵坐标

							const vector = new THREE.Vector3(mouseX, mouseY, 0.5);
							vector.unproject(camera);

							const dir = vector.sub(camera.position).normalize();
							const distance = -camera.position.z / dir.z;
							const pos = camera.position.clone().add(dir.multiplyScalar(distance));

							if (chooseMeshArr.length >= 1) {
								drawLine(chooseMeshArr[chooseMeshArr.length - 1].position.clone(), pos);
							}
						}
					}

					function onDocumentMouseDown(event) {
						isDragging = true;
						onDocumentMouseMove(event); // 更新线段位置到鼠标位置
					}

					function onDocumentMouseUp(event) {
						isDragging = false;
						scene.remove(currentLine);
						chooseMeshArr = [];
					}
				}


				// const controls = new OrbitControls(camera, renderer.domElement);
				var frameCount = 10; // GIF 动画帧数
				var currentFrame = 0;

				function updateGifTexture() {
					currentFrame = (currentFrame + 1) % frameCount;
					var offsetX = 1 / frameCount * currentFrame;
					texture.offset.set(offsetX, 0);
				}

				// 渲染循环
				function render() {
					renderer.render(scene, camera);
					requestAnimationFrame(render);
					if (Date.now() - lastFrameChangeTime > frameDelay) {
						planeMaterial.map = textures[frameIndex];
						frameIndex = (frameIndex + 1) % frameCount;
						lastFrameChangeTime = Date.now();
					}
					TWEEN.update();
				}
				render();

				// 画布跟随窗口变化
				window.onresize = function() {
					const width = that.canvasWidth;
					const height = that.canvasWidth;

					// cnavas画布宽高度重新设置
					renderer.setSize(width, height);
					camera.aspect = width / height;
					camera.updateProjectionMatrix();

					const spriteWidth = (width) / guiParams.cols; // 精灵的宽度  
					const spriteHeight = (width) / guiParams.rows; // 精灵的高度
				};
			},

			bbbbb() {
				console.log('执行了bbbbb方法')
			},
		}
	}
</script>

<style>

</style>